package main

import (
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"log"
)

//<REQUEST,o,t,c>
type Request struct {
	Message
	//操作，标记不同操作：查询，共识，新节点....
	Operation  operation
	//请求发送时间戳
	Timestamp  int64
	//目的client地址？
	ClientAddr string
	//节点签名
	Sign	   []byte
}

//<PRE-PREPARE,v,n,d>
type PrePrepare struct {
	View			int
	SequenceID		int64
	Digest         	string
}



//<<PRE-PREPARE,v,n,d>,m>
type PrePrepareRequest struct {
	PrePrepareMessage	PrePrepare
	RequestMessage		Request
	Sign           		[]byte
}

//<PREPARE,v,n,d,i>
type Prepare struct {
	View 		int
	SequenceID	int64
	Digest     	string
	NodeID     	int
	Sign       	[]byte
}

//<COMMIT,v,n,D(m),i>
type Commit struct {
	View 		int
	SequenceID	int64
	Digest     	string
	NodeID     	int
	Sign       	[]byte
}

//<REPLY,v,t,c,i,r>
type Reply struct {
	View      			int
	Timestamp 			int64
	ClientAddress		string
	NodeID    			int
	ResponseMessage   	Response
	Sign    	   		[]byte
}

type Response struct{
	Type			operation
	//newNode reply
	NodeCount		int
	NodeAddr		string
	//newTra reply
	Response  		string
	SequenceID 		int64
}

//<CHECKPOINT,n,d,i>
type CheckPoint struct{
	SequenceID		int64
	Digest			string
	NodeID			int
	Sign			[]byte
}

//<VIEW-CHANGE,v+1,n,C,P,i>
type ViewChange struct{
	View			int
	SequenceID		int64
	CheckPointSet	string
	PrePrepareSet	string
	NodeID			int
}

//<NEW-VIEW,v+1,V,O>
type NewView struct{
	View			int
	ViewChangeSet	string
	PrePrepareSet	string
	Sign 			[]byte
}

type Message struct {
	Content 		string
	//SequenceID		int64
	Digest      	string
	//MessageHash		string
}


type Query struct{
	//查询类型，默认为“newTra"
	QueryType 		operation
	//序列号
	SequenceID		int64
	//请求发送时间戳
	Timestamp 		int64
	//相当于clientID
	ClientAddr 		string
	//查询结果存放出
	QueryReply 		string
	//查询后副节点签名处
	NodeId 			int
	Sign 			[]byte
}


//here
const prefixCMDLength = 12
const checkedTailLength = 8
const checkedTag = "checked"

type command string

const (
	cRequest    command = "request"
	cPrePrepare command = "prePrepare"
	cPrepare    command = "prepare"
	cCommit     command = "commit"
	cReply		command = "reply"
	cViewChange	command = "viewChange"
	cNewView	command = "newView"
	cCheckPoint	command = "checkPoint"
	cQuery		command = "query"
)

type operation string
const (
	oNewNode 		operation = "newNode"
	oNewTra  		operation = "newTra"
	oVerTra  		operation = "verTra"
	oViewChange		operation = "viewChange"
	oTransaction    operation = "transaction"
)

//默认前十二位为命令名称
func jointMessage(cmd command, content []byte) []byte {
	b := make([]byte, prefixCMDLength)
	for i, v := range []byte(cmd) {
		b[i] = v
	}
	joint := make([]byte, 0)//???????
	joint = append(b, content...)
	return joint
}

//默认前十二位为命令名称
func splitMessage(message []byte) (cmd string, content []byte) {
	cmdBytes := message[:prefixCMDLength]
	newCMDBytes := make([]byte, 0)
	for _, v := range cmdBytes {
		if v != byte(0) {
			newCMDBytes = append(newCMDBytes, v)
		}
	}
	cmd = string(newCMDBytes)
	content = message[prefixCMDLength:]
	return
}

//对消息详情进行摘要
func getDigest(request Request) string {
	b, err := json.Marshal(request)
	if err != nil {
		log.Panic(err)
	}
	hash := sha256.Sum256(b)
	//进行十六进制字符串编码
	return hex.EncodeToString(hash[:])
}

//数据段最后八位作为checked
func jointTail(content []byte) []byte {
	b := make([]byte, checkedTailLength)
	for i, v := range []byte(checkedTag) {
		b[i] = v
	}
	joint := make([]byte, 0)//???????
	joint = append(content, b...)
	return joint
}

//默认前十二位为命令名称
func VeriTail(message []byte) (isTrue bool, content []byte) {
	isTrue = false
	len := len(message)
	cmdBytes := message[len - checkedTailLength:]
	newCMDBytes := make([]byte, 0)
	for _, v := range cmdBytes {
		if v != byte(0) {
			newCMDBytes = append(newCMDBytes, v)
		}
	}
	cmd := string(newCMDBytes)
	if cmd == checkedTag{
		isTrue = true
	}
	content = message[:len - checkedTailLength]
	return
}
